﻿using AdminBlazor.Configs;
using AdminBlazor.Files;
using AdminBlazor.Infrastructure.Encrypt;
using BootstrapBlazor.Components;
using FreeSql;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OBS;
using OnceMi.AspNetCore.OSS;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.PixelFormats;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Jpeg;
using MimeKit;

namespace AdminBlazor.Services;

public class FileService : BaseService
{
    private readonly IBaseRepository<FileEntity,long> _fileRepository;
    private readonly OSSConfig _oSSConfig;
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly IWebHostEnvironment _webHostEnvironment;

    public FileService(IBaseRepository<FileEntity, long> fileRepository,
        IOptions<OSSConfig> oSSConfig, IHttpContextAccessor httpContextAccessor, IWebHostEnvironment webHostEnvironment, AdminContext admin) : base(admin)
    {
        _fileRepository = fileRepository;
        _httpContextAccessor = httpContextAccessor;
        _oSSConfig = oSSConfig.Value;
        _webHostEnvironment = webHostEnvironment;
    }

    /// <summary>
    /// 获取上传目录的所有子目录
    /// </summary>
    /// <returns></returns>
    public List<TreeItem> GetGroups()
    {
        var localUploadConfig = _oSSConfig.LocalUploadConfig;
        var env = _webHostEnvironment;
        var fileDirectory = Path.Combine(env.WebRootPath, localUploadConfig.Directory).ToPath();
        var result = new List<TreeItem>() { new TreeItem { Text="所有文件" } };

        foreach (var item in Directory.GetDirectories(fileDirectory)) {
            result.Add(new TreeItem { Text=item.Replace(Path.Combine(env.WebRootPath, localUploadConfig.Directory).ToPath(), "")  });
        }

        return result;
    }

    /// <summary>
    /// 添加分组
    /// </summary>
    /// <param name="groupName"></param>
    public void AddGroup(string groupName) {
        var env = _webHostEnvironment;
        var localUploadConfig = _oSSConfig.LocalUploadConfig;

        string fileDirectory = localUploadConfig.Directory;
        fileDirectory = Path.Combine(env.WebRootPath, fileDirectory, groupName).ToPath();
        if (!Directory.Exists(fileDirectory))
        {
            Directory.CreateDirectory(fileDirectory);
        }
    }

    /// <summary>
    /// 上传文件
    /// </summary>
    /// <param name="file">文件</param>
    /// <param name="fileDirectory">文件目录</param>
    /// <param name="fileReName">文件重命名</param>
    /// <returns></returns>
    public async Task<FileEntity> UploadFileAsync(UploadFile file, string fileDirectory = "", bool fileReName = true)
    {
        //if (!_admin.IsLogin())
        //{
        //    throw ResultOutput.Exception("未授权用户禁止执行");
        //}

        if (fileDirectory == "所有文件") fileDirectory = "";

        var localUploadConfig = _oSSConfig.LocalUploadConfig;

        var extention = file.GetExtension()?.ToLower();
        var hasIncludeExtension = localUploadConfig.IncludeExtension?.Length > 0;
        if (hasIncludeExtension && !localUploadConfig.IncludeExtension.Contains(extention))
        {
            throw ResultOutput.Exception($"不允许上传{extention}文件格式");
        }
        var hasExcludeExtension = localUploadConfig.ExcludeExtension?.Length > 0;
        if (hasExcludeExtension && localUploadConfig.ExcludeExtension.Contains(extention))
        {
            throw ResultOutput.Exception($"不允许上传{extention}文件格式");
        }

        var fileLenth = file.Size;
        if (fileLenth > localUploadConfig.MaxSize)
        {
            throw ResultOutput.Exception($"文件大小不能超过{new FileSize(localUploadConfig.MaxSize)}");
        }

        var oSSOptions = _oSSConfig.OSSConfigs.Where(a => a.Enable && a.Provider == _oSSConfig.Provider).FirstOrDefault();
        var enableOss = oSSOptions != null && oSSOptions.Enable;
        var enableMd5 = enableOss ? oSSOptions.Md5 : localUploadConfig.Md5;
        var md5 = string.Empty;
        if (enableMd5)
        {
            md5 = Md5Encrypt.GetHash(file.File.OpenReadStream());
            var md5FileEntity = await _fileRepository.WhereIf(enableOss, a => a.Provider == oSSOptions.Provider).Where(a => a.Md5 == md5).FirstAsync();
            if (md5FileEntity != null)
            {
                var sameFileEntity = new FileEntity
                {
                    Provider = md5FileEntity.Provider,
                    BucketName = md5FileEntity.BucketName,
                    FileGuid = FreeUtil.NewMongodbId(),
                    SaveFileName = md5FileEntity.SaveFileName,
                    FileName = file.OriginFileName,
                    Extension = extention,
                    FileDirectory = md5FileEntity.FileDirectory,
                    Size = md5FileEntity.Size,
                    SizeFormat = md5FileEntity.SizeFormat,
                    LinkUrl = md5FileEntity.LinkUrl,
                    Md5 = md5,
                };
                sameFileEntity = await _fileRepository.InsertAsync(sameFileEntity);
                return sameFileEntity;
            }
        }

        if (fileDirectory.IsNull())
        {
            fileDirectory = localUploadConfig.Directory;
            if (localUploadConfig.DateTimeDirectory.NotNull())
            {
                fileDirectory = Path.Combine(fileDirectory, DateTime.Now.ToString(localUploadConfig.DateTimeDirectory)).ToPath();
            }
        }
        else
        {
            fileDirectory = Path.Combine(localUploadConfig.Directory, fileDirectory.Replace("\\","").Replace("/", "")).ToPath();
        }

        var fileSize = new FileSize(fileLenth);
        var fileEntity = new FileEntity
        {
            Provider = oSSOptions?.Provider,
            BucketName = oSSOptions?.BucketName,
            FileGuid = FreeUtil.NewMongodbId(),
            FileName = file.OriginFileName,
            Extension = extention,
            FileDirectory = fileDirectory,
            Size = fileSize.Size,
            SizeFormat = fileSize.ToString(),
            Md5 = md5
        };
        fileEntity.SaveFileName = fileReName ? fileEntity.FileGuid.ToString() : fileEntity.FileName;

        var filePath = Path.Combine(fileDirectory, fileEntity.SaveFileName + (fileReName ? file.IsImage() ? ".jpeg":fileEntity.Extension :"")).ToPath();
        var url = string.Empty;
        if (enableOss)
        {
            url = oSSOptions.Url;
            if (url.IsNull())
            {
                url = oSSOptions.Provider switch
                {
                    OSSProvider.Minio => $"{oSSOptions.Endpoint}/{oSSOptions.BucketName}",
                    OSSProvider.Aliyun => $"{oSSOptions.BucketName}.{oSSOptions.Endpoint}",
                    OSSProvider.QCloud => $"{oSSOptions.BucketName}-{oSSOptions.Endpoint}.cos.{oSSOptions.Region}.myqcloud.com",
                    OSSProvider.Qiniu => $"{oSSOptions.BucketName}.{oSSOptions.Region}.qiniucs.com",
                    OSSProvider.HuaweiCloud => $"{oSSOptions.BucketName}.{oSSOptions.Endpoint}",
                    _ => ""
                };

                if (url.IsNull())
                {
                    throw ResultOutput.Exception($"请配置{oSSOptions.Provider}的Url参数");
                }

                var urlProtocol = oSSOptions.IsEnableHttps ? "https" : "http";
                fileEntity.LinkUrl = $"{urlProtocol}://{url}/{filePath}";
            }
            else
            {
                fileEntity.LinkUrl = $"{url}/{filePath}";
            }
        }
        else
        {
            fileEntity.LinkUrl = $"/{filePath}";
        }

        if (enableOss)
        {
            var _oSSServiceFactory = _httpContextAccessor.HttpContext.RequestServices.GetRequiredService<IOSSServiceFactory>();
            var oSSService = _oSSServiceFactory.Create(_oSSConfig.Provider.ToString());
            await oSSService.PutObjectAsync(oSSOptions.BucketName, filePath, file.File.OpenReadStream());
        }
        else
        {
            var env = _webHostEnvironment;
            fileDirectory = Path.Combine(env.WebRootPath, fileDirectory).ToPath();
            if (!Directory.Exists(fileDirectory))
            {
                Directory.CreateDirectory(fileDirectory);
            }
            filePath = Path.Combine(env.WebRootPath, filePath).ToPath();
            //保存到磁盘
            await file.SaveToFileAsync(filePath, localUploadConfig.MaxSize);

            //如果是图片则压缩
            if (file.IsImage())
            {
                // 加载图像  
                using (var image = await Image.LoadAsync(filePath))
                {
                    var w = image.Width;
                    var h = image.Height;

                    if (w > 1600)
                    {
                        // 调整图像大小  
                        image.Mutate(x => x.Resize(1600, 0, true));

                        var encoder = new JpegEncoder
                        {
                            Quality = 90
                        };

                        // 覆盖原图  
                        await image.SaveAsJpegAsync(filePath, encoder);

                        fileSize = new FileSize(new System.IO.FileInfo(filePath).Length);
                        fileEntity.Size = fileSize.Size;
                        fileEntity.SizeFormat = fileSize.ToString();
                    }
                }
            }
        }

        if(await _fileRepository.Select.AnyAsync(x=>x.FileName == fileEntity.FileName))
        {
            fileEntity.FileName = fileEntity.FileName.Replace(".", "_" + new Random().Next(1000, 9999)+".");
        }

        fileEntity = await _fileRepository.InsertAsync(fileEntity);

        return fileEntity;
    }

    /// <summary>
    /// 上传多文件
    /// </summary>
    /// <param name="files">文件列表</param>
    /// <param name="fileDirectory">文件目录</param>
    /// <param name="fileReName">文件重命名</param>
    /// <returns></returns>
    public async Task<List<FileEntity>> UploadFilesAsync(List<UploadFile> files, string fileDirectory = "", bool fileReName = true)
    {
        var fileList = new List<FileEntity>();
        foreach (var file in files)
        {
            fileList.Add(await UploadFileAsync(file, fileDirectory, fileReName));
        }
        return fileList;
    }

    /// <summary>
    /// 删除
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpPost]
    public async Task DeleteAsync(long id)
    {
        var file = await _fileRepository.GetAsync(id);
        if (file == null)
        {
            return;
        }

        if (file.Provider.HasValue)
        {
            var _oSSServiceFactory = _httpContextAccessor.HttpContext.RequestServices.GetRequiredService<IOSSServiceFactory>();
            var oSSService = _oSSServiceFactory.Create(file.Provider.ToString());
            var oSSOptions = _oSSConfig.OSSConfigs.Where(a => a.Enable && a.Provider == file.Provider).FirstOrDefault();
            var enableOss = oSSOptions != null && oSSOptions.Enable;
            if (enableOss)
            {
                var filePath = Path.Combine(file.FileDirectory, file.SaveFileName + file.Extension).ToPath();
                await oSSService.RemoveObjectAsync(file.BucketName, filePath);
            }
        }
        else
        {
            var env = _webHostEnvironment;
            var filePath = Path.Combine(env.WebRootPath,file.FileDirectory, file.SaveFileName.Replace(file.Extension, "")+file.Extension).ToPath();
            if (System.IO.File.Exists(filePath))
            {
                System.IO.File.Delete(filePath);
            }
        }

        await _fileRepository.DeleteAsync(file.Id);
    }
}